use std::io::Write;
use mysql::Value;
use chrono::Local;
use tera::Context;
use actix_files::NamedFile;
use actix_session::Session;
use actix_multipart::Multipart;
use actix_web::{
    get, post, Responder, Result,
    web::{Form, Path, block}
};
use futures::{StreamExt, TryStreamExt};
use crate::rules::Vo;
use crate::util::{ctx, G_CACHE, redirect, to_json_obj};
use crate::system::dao as systemDao;
use crate::users::dao as userDao;

// 404页面
pub async fn into_404(session: Session) -> impl Responder {
    render!("index/404.html", &ctx(Context::new(), &session))
}

// 首页
pub async fn index() -> impl Responder {
    render!("index/login.html")
}

// 系统图片
#[get("/imgs/{img}")]
pub async fn imgs(Path(img): Path<String>) -> Result<NamedFile> {
    Ok(NamedFile::open(format!("webapp/img/{}", img))?)
}

// 登录
#[post("/login.html")]
pub async fn login(session: Session, data: Form<Vo>) -> Result<impl Responder> {
    let user = userDao::get_user(
        "id,name,department,telephone,statu",
        data.str("username"),
        data.str("password"),
    );
    if user.empty() {
        return Ok(to_json_obj(map!{"code"=>"50", "msg"=>"用户名或密码输入不正确"}));
    } else if user.str("statu") == "离职" {
        return Ok(to_json_obj(map!{"code"=>"50", "msg"=>"离职人员禁止登录系统"}));
    }
    let user_id = user.long("id");
    let map = map! {
        "userId" => Value::from(user_id),
        "userName" => Value::from(user.str("name")),
        "midified" => Value::from("登录系统"),
        "module" => Value::from("PC端日志"),
        "types" => Value::from(1),
        "createTime" => Value::from(Local::now().naive_local())
    };
    let log_id = systemDao::save_log(&map);
    let key = format!("menus{}", user_id);
    G_CACHE.insert(key, userDao::menus(user_id));
    session.set("userId", user_id)?;
    session.set("logId", log_id)?;
    session.set("user", user)?;
    session.set("flag", 1_u8)?;

    return Ok(to_json_obj(map! {"code"=>"20"}));
}

// 框架页
#[get("/main.html")]
pub async fn main(session: Session) -> impl Responder {
    render!("index/main.html", &ctx(Context::new(), &session))
}

// 框架页加载完成后,下次将从sessionStorage中获取菜单列表
#[post("/ajaxMenu.html")]
pub async fn ajax_menu(session: Session, data: String) -> Result<impl Responder> {
    if data.is_empty() {
        session.set("flag", 2_u8)?;
    } else {
        let user_id: u32 = session.get("userId")?.unwrap();
        let key = format!("menus{}", user_id);
        G_CACHE.insert(key, userDao::menus(user_id));
        session.set("flag", 1_u8)?;
    }

    Ok(to_json_obj(map! {"code"=>"20"}))
}

// 退出
#[get("/quit.html")]
pub async fn quit(session: Session) -> impl Responder {
    session.clear();
    
    redirect(crate::CONTEXT_PATH)
}

// 显示头像
#[get("/tmp/{photo}")]
pub async fn show_photo(Path(photo): Path<String>) -> Result<NamedFile> {
    Ok(NamedFile::open(format!("tmp/{}", photo))?)
}

// 上传附件
#[post("/uploadFile.html")]
pub async fn upload_file(mut payload: Multipart) -> Result<impl Responder> {
    let mut realname = String::new();
    while let Ok(Some(mut field)) = payload.try_next().await {
        realname = format!("{}.jpg", Local::now().timestamp());
        let filepath = format!("tmp/{}", realname);

        let mut f = block(|| std::fs::File::create(filepath))
            .await?;

        while let Some(chunk) = field.next().await {
            let data = chunk?;
            f = block(move || f.write_all(&data).map(|_| f)).await?;
        }
    }
    
    Ok(to_json_obj(map! {"code"=>"20", "realname"=>&realname}))
}
